/**
 * Created on 20/04/2008
 * 
 */
package com.apbetioli.mapr.place.control;

import com.apbetioli.mapr.place.control.kml.KMLGenerator;
import com.apbetioli.mapr.place.dao.PlacesDao;
import com.apbetioli.mapr.place.dao.PlacesDaoFactory;
import com.apbetioli.mapr.place.dao.PlacesDaoInterface;
import com.apbetioli.mapr.place.entity.Place;
import com.apbetioli.mapr.place.exception.GeocodingException;
import com.apbetioli.mapr.project.dao.ProjectsDao;
import com.apbetioli.mapr.project.entity.Project;
import com.apbetioli.mapr.place.schema.CtAction;
import com.apbetioli.mapr.place.schema.CtDelete;
import com.apbetioli.mapr.place.schema.CtFindByName;
import com.apbetioli.mapr.place.schema.CtListAll;
import com.apbetioli.mapr.place.schema.CtPlace;
import com.apbetioli.mapr.place.schema.CtResponse;
import com.apbetioli.mapr.place.schema.CtResponseList;
import com.apbetioli.mapr.place.schema.CtSave;
import com.apbetioli.mapr.place.schema.PlacesManager;
import com.apbetioli.mapr.place.schema.StAction;
import com.apbetioli.mapr.place.schema.StStatus;
import com.apbetioli.mapr.project.dao.ProjectsDaoFactory;
import com.apbetioli.mapr.project.dao.ProjectsDaoInterface;
import com.apbetioli.mapr.util.ErrorsEnum;
import com.apbetioli.mapr.util.properties.PropertiesLoaderImpl;
import java.io.FileNotFoundException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBException;

/**
 *
 * @author Alexandre Parra Betioli
 */
public final class PlacesControl {
    
    private PlacesDaoInterface placesDao;
    private ProjectsDaoInterface projectsDao;
    
    public PlacesControl() {
        this( true );
    }
    
    //Package private constructor. Used for unit tests.
    PlacesControl( final boolean useTransactions ) {
        placesDao   = PlacesDaoFactory.getInstance(useTransactions);
        projectsDao = ProjectsDaoFactory.getInstance(useTransactions);
    }

    public PlacesManager process( final PlacesManager input, final String projectKey ) throws JAXBException, FileNotFoundException {
        
        //Validate input
        
        ErrorsEnum e = null;
        
        Project project = projectsDao.findByKey(projectKey);
 
        if( project == null )
            e = ErrorsEnum.PROJECT_NOT_FOUND;
        
        if ( input.getActionList() == null )
            e = ErrorsEnum.WRONG_INPUT;
        
        if( e != null )
            return e.getPlacesManagerError();
        
        //Prepare output
        
        PlacesManager  output       = new PlacesManager();
        CtResponseList responseList = new CtResponseList();
        output.setResponseList(responseList);        
        
        //Process
        
        for( CtAction action : input.getActionList().getSaveOrDeleteOrFindByName() ) {
            CtResponse response = processAction( action, project );
            responseList.getResponse().add(response);
        }
        
        //Generate Kml
        
        KMLGenerator kg = new KMLGenerator();
        kg.generate(getPlacesDao().listAll(), projectKey);
        
        return output;
    }

    private CtResponse processAction( final CtAction action, final Project project) {

        CtResponse response = new CtResponse();
        
        if( action instanceof CtSave )
            response = save( (CtSave)action, project );
        
        else if ( action instanceof CtDelete )
            response = delete( (CtDelete)action );
            
        else if ( action instanceof CtFindByName )
            response = findByName( (CtFindByName) action );
        
        else if ( action instanceof CtListAll )
            response = listAll( (CtListAll) action );
        
        else {
            //All the actions are should be listed above, so else won't be reached.
        }
        
        return response;
        
    }

    private CtResponse save( final CtSave ctSave, final Project project) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.SAVE );

        try {
            CtPlace ctPlace  = ctSave.getPlace();
            Place   place    = new Place();

            place.parse( ctPlace );
            place.geocode();
            
            place.setProject(project);
            
            Place old = getPlacesDao().save(place);
            
            if( old == null)
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "place.action.added") );
            else
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "place.action.updated") );

            response.getPlace().add( place.clone() );
            response.setStatus( StStatus.SUCCESS );
        }
        catch( GeocodingException e ) {
            Logger.getLogger(PlacesControl.class.getName()).log(Level.WARNING, null, e);
            response.setMessage( PropertiesLoaderImpl.getValue("exceptions.properties", "geocoding") );
            response.setStatus( StStatus.FAILURE );
        }
        catch( UnknownHostException e ) {
            Logger.getLogger(PlacesControl.class.getName()).log(Level.WARNING, null, e);
            response.setMessage( PropertiesLoaderImpl.getValue("exceptions.properties", "unknownHost") );
            response.setStatus( StStatus.FAILURE );
        }
        catch( Exception e ) {
            Logger.getLogger(PlacesControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }
    
    private CtResponse delete( final CtDelete ctDelete) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.DELETE );

        try {
            String name    = ctDelete.getName();
            Place  deleted = getPlacesDao().delete(name);
            
            if( deleted == null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "place.action.fail.findByName") +  ": " + name);
                response.setStatus( StStatus.FAILURE );
            }
            else {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "place.action.deleted") );
                response.getPlace().add( deleted.clone() );
                response.setStatus( StStatus.SUCCESS );
            }
        }
        catch( Exception e ) {
            Logger.getLogger(PlacesControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }

    private CtResponse findByName( final CtFindByName ctFindByName) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.FIND_BY_NAME );

        try {
            String name  = ctFindByName.getName();
            Place  found = getPlacesDao().findByName(name);
            
            if( found == null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "place.action.fail.findByName") +  ": " + name);
                response.setStatus( StStatus.FAILURE );
            }
            else {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "place.action.findByName") );
                response.getPlace().add( found.clone() );
                response.setStatus( StStatus.SUCCESS );
            }
        }
        catch( Exception e ) {
            Logger.getLogger(PlacesControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }

    private CtResponse listAll(CtListAll ctListAll) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.LIST_ALL );

        try {
            List<Place> list = getPlacesDao().listAll();
            
            int numberOfPlacesFound = 0;
            
            if( list != null ) {
                for( Place place : list ) {
                    response.getPlace().add( place.clone() );
                }
                
                numberOfPlacesFound = list.size();
            }
            
            response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "place.action.listAll") +  ": " + numberOfPlacesFound);
            response.setStatus( StStatus.SUCCESS );
        }
        catch( Exception e ) {
            Logger.getLogger(PlacesControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }

    public PlacesDaoInterface getPlacesDao() {
        return placesDao;
    }

}
